﻿using CleanArchitecture.Infrastructure.Models;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
using System.Reflection;
using System.Threading.Tasks;

namespace CleanArchitecture.Infrastructure.ModelBinding
{
    /// <summary>
    /// Represents model binder for the binding models inherited from the BaseNopModel
    /// </summary>
    public class MvcModelBinder : IModelBinder
    {
        private readonly BodyModelBinder _bodyModelBinder;
        private readonly ComplexTypeModelBinder _complexTypeModelBinder;
        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="propertyBinders">Property binders</param>
        public MvcModelBinder(ComplexTypeModelBinder complexBinder, BodyModelBinder bodyBinder = null)
        {
            this._complexTypeModelBinder = complexBinder;
            this._bodyModelBinder = bodyBinder;
        }

        #endregion

        #region Methods
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if(this._bodyModelBinder != null)
            {
                await this._bodyModelBinder.BindModelAsync(bindingContext);
                if (bindingContext.Result.IsModelSet)
                    bindingContext.Model = bindingContext.Result.Model;
            }

            await this._complexTypeModelBinder.BindModelAsync(bindingContext);
            object model = null;
            if(bindingContext.Result.IsModelSet)
                model = bindingContext.Result.Model;

            if (model != null && model is BaseEntityModel)
            {
                //add custom model binding
                (model as BaseEntityModel).BindModel(bindingContext);
                //trim property string values for BaseEntityModel
                //var modelType = bindingContext.ModelMetadata.ModelType;
                PropertyInfo[] modelProps = model.GetType().GetProperties();
                foreach(PropertyInfo pi in modelProps)
                {
                    if (!pi.IsDefined(typeof(NoTrimAttribute), false)) continue;
                    // 获取属性的值
                    var propertyValue = pi.GetValue(model) as string;
                    if (!string.IsNullOrEmpty(propertyValue))
                        pi.SetValue(model, propertyValue.Trim(), null);
                }
                bindingContext.Model = model;
            }
        }
        #endregion
    }
}
